unit Grid;

interface
uses
  Classes, Grids, Graphics, QTable;

type

  TGridItem = class
    private
      FImage    : TBitmap;
      FHistory  : TList;

      FState    : TState;

    public
      constructor Create (ItemType : string; Row, Col : Integer);
      destructor Destroy; override;

      property State : TState read FState;
      property Image : TBitmap read FImage write FImage;
      property History : TList read FHistory write FHistory;
  end;

  TGrid = class
  private
    FCols,
    FRows       : Integer;

    FAgenteList : TList;
    FGridItems : array of array of TGridItem;
    function GetGridItem(Row, Col : Integer): TGridItem;
    function ValidState(StateType: TStateType) : Boolean;
    function GetRandomState (ValidOnly : Boolean = True) : TState;
  public
    constructor Create;
    destructor Destroy; override;
    procedure LoadFromStringGrid (StringGrid : TStringGrid; Clean : Boolean = False);

    function ChangeState (State : TState; Action : TAction) : TState;

    function GetInitialState (ValidOnly : Boolean = True) : TState;
    property Rows : Integer read FRows;
    property Cols : Integer read FCols;
    property Items [Row, Col : Integer] : TGridItem read GetGridItem; default;
  end;

const
  BLANK   = '';
  MONSTER = '#';
  GOLD    = '*';
  HOLE    = '0';

implementation
uses
  SysUtils;

{ TGrid }

function TGrid.ChangeState(State: TState; Action: TAction): TState;
begin
  Result := State;
  case Action of
    acUp :
      begin
        if (State.Row - 1) >= 0 then
          begin
            Result := FGridItems [State.Row - 1, State.Col].FState;
          end;
      end;

    acRight :
      begin
        if (State.Col + 1) < FCols then
          begin
            Result := FGridItems [State.Row, State.Col + 1].FState;
          end;
      end;

    acDown :
      begin
        if (State.Row + 1) < FRows then
          begin
            Result := FGridItems [State.Row + 1, State.Col].FState;
          end;
      end;

    acLeft :
      begin
        if (State.Col - 1) >= 0 then
          begin
            Result := FGridItems [State.Row, State.Col - 1].FState;
          end;
      end;
  end;
end;

constructor TGrid.Create;
begin
  FAgenteList := TList.Create;
  FRows := 0;
  FCols := 0;
end;

destructor TGrid.Destroy;
var
  Ix, Jx : Integer;
begin
  for Ix := 0 to Rows-1 do
    begin
      for Jx := 0 to Cols-1 do
        begin
          FreeAndNil (FGridItems [Ix, Jx]);
        end;
    end;
  inherited;
end;

function TGrid.GetGridItem(Row, Col : Integer): TGridItem;
begin
  Result := FGridItems [Row, Col];
end;

function TGrid.GetInitialState(ValidOnly: Boolean): TState;
begin
  Result := GetRandomState(ValidOnly);
end;

function TGrid.GetRandomState(ValidOnly: Boolean): TState;
var
  Row, Col : Integer;
begin
  Row := Random (Rows);
  Col := Random (Cols);

  Result := FGridItems [Row, Col].FState;

  while (ValidOnly) and not (ValidState(Result.StateType)) do
    begin
      Row := Random (Rows);
      Col := Random (Cols);

      Result := FGridItems [Row, Col].FState;

    end;

end;

procedure TGrid.LoadFromStringGrid(StringGrid: TStringGrid; Clean : Boolean);
var
  Ix,
  Jx : Integer;

begin

  for Ix := 0 to FRows-1 do
    begin
      for Jx := 0 to FCols-1 do
        begin
          FreeAndNil(FGridItems[Ix, Jx]);
        end;
    end;

  FCols := StringGrid.ColCount;
  FRows := StringGrid.RowCount;
  SetLength (FGridItems, FRows, FCols);

  for Ix := 0 to FRows-1 do
    begin
      for Jx := 0 to FCols-1 do
        begin
          FGridItems[Ix, Jx] := TGridItem.Create (StringGrid.Cells[Jx, Ix], Ix, Jx);
          if Clean then
            StringGrid.Cells[Jx, Ix] := '';
        end;
    end;
end;

function TGrid.ValidState(StateType: TStateType): Boolean;
begin
  Result := (StateType <> stWall) and
            (StateType <> stHole) and
            (StateType <> stMonster) and
            (StateType <> stGold);
end;

{ TGridItem }

constructor TGridItem.Create(ItemType: string; Row, Col : Integer);
const

  NO_REWARD       = 0;
  MONSTER_REWARD  = -100;
  GOLD_REWARD     = 100;

begin

  FHistory  := TList.Create;
  FState    := TState.Create(Row, Col);
  FImage := TBitmap.Create;
  FImage.TransparentColor := clFuchsia;
  FImage.Transparent := True;

  if ItemType = BLANK then
    begin
      //FImage.LoadFromFile('C:\Arquivos de programas\Borland\Delphi7\Projects\Projeto Final\src\Images\red.bmp');
      FreeAndNil(FImage);
      FState.Reward := NO_REWARD;
      FState.StateType := stClean;
    end
  else if ItemType = MONSTER then
    begin
      FImage.LoadFromFile('Images\brown.bmp');
      FState.Reward := MONSTER_REWARD;
      FState.StateType := stMonster;
    end
  else if ItemType = GOLD then
    begin
      FImage.LoadFromFile('Images\yellow.bmp');
      FState.Reward := GOLD_REWARD;
      FState.StateType := stGold;
    end;
end;

destructor TGridItem.Destroy;
begin
  FreeAndNil (FHistory);
  FreeAndNil (FState);
  FreeAndNil (FImage);
  
  inherited;
end;

end.
